package core;

import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 集合操作工具类（空值安全优化版）
 * <p>
 * 提供集合判空、分组、安全访问等操作，所有方法均进行空值安全处理。
 * 参考Hutool的CollUtil类实现，提供丰富的集合处理方法。
 * 针对大数据量场景，提供了并行处理优化。
 * </p>
 */
public final class CollectionUtil {
    // 大数据量阈值，超过此值将使用并行处理
    private static final int PARALLEL_THRESHOLD = 100000;

    private CollectionUtil() {
        throw new AssertionError("Utility class");
    }

    /**
     * 集合判空（空值安全）
     *
     * @param coll 待检查集合
     * @return 集合为null或空时返回true
     */
    public static boolean isEmpty(Collection<?> coll) {
        return coll == null || coll.isEmpty();
    }

    /**
     * Map判空（空值安全）
     *
     * @param map 待检查Map
     * @return Map为null或空时返回true
     */
    public static boolean isEmpty(Map<?, ?> map) {
        return map == null || map.isEmpty();
    }

    /**
     * 集合非空判断（空值安全）
     *
     * @param coll 待检查集合
     * @return 集合非空时返回true
     */
    public static boolean isNotEmpty(Collection<?> coll) {
        return !isEmpty(coll);
    }

    /**
     * 集合判空（空值安全）
     *
     * @param coll 待检查集合
     * @return 集合为null或空时返回true
     */
    public static boolean isBlank(Collection<?> coll) {
        if (isEmpty(coll)) {
            return true;
        }
        // 大数据量时使用并行流
        if (coll.size() > PARALLEL_THRESHOLD) {
            return coll.parallelStream().allMatch(ObjectUtil::isEmpty);
        }
        return coll.stream().allMatch(ObjectUtil::isEmpty);
    }

    /**
     * Map非空判断（空值安全）
     *
     * @param coll 待检查集合
     * @return 集合非空时返回true，包括里面的数据也要非空
     */
    public static boolean isNotBlank(Collection<?> coll) {
        return !isBlank(coll);
    }

    /**
     * Map非空判断（空值安全）
     *
     * @param map 待检查Map
     * @return Map非空时返回true
     */
    public static boolean isNotEmpty(Map<?, ?> map) {
        return !isEmpty(map);
    }

    /**
     * 如果提供的集合为{@code null}，返回一个不可变的默认空集合，否则返回原集合
     *
     * @param <T>  集合元素类型
     * @param coll 提供的集合，可能为null
     * @return 原集合，若为null返回空集合
     */
    public static <T> Collection<T> emptyIfNull(Collection<T> coll) {
        return (null == coll) ? Collections.emptyList() : coll;
    }

    /**
     * 如果提供的Map为{@code null}，返回一个不可变的默认空Map，否则返回原Map
     *
     * @param <K> Map键类型
     * @param <V> Map值类型
     * @param map 提供的Map，可能为null
     * @return 原Map，若为null返回空Map
     */
    public static <K, V> Map<K, V> emptyIfNull(Map<K, V> map) {
        return (null == map) ? Collections.emptyMap() : map;
    }

    /**
     * 两个集合的并集
     * 针对一个集合中存在多个相同元素的情况，计算两个集合中此元素的个数，保留最多的个数
     *
     * @param <T>   集合元素类型
     * @param coll1 集合1
     * @param coll2 集合2
     * @return 并集的集合，返回 {@link ArrayList}
     */
    public static <T> Collection<T> union(Collection<T> coll1, Collection<T> coll2) {
        if (isEmpty(coll1) && isEmpty(coll2)) return Collections.emptyList();
        if (isEmpty(coll1)) return new ArrayList<>(coll2);
        if (isEmpty(coll2)) return new ArrayList<>(coll1);

        final boolean useParallel = coll1.size() + coll2.size() > PARALLEL_THRESHOLD;
        final Map<T, Integer> map1 = countMap(coll1, useParallel);
        final Map<T, Integer> map2 = countMap(coll2, useParallel);

        Set<T> allElements = new HashSet<>(coll1);
        allElements.addAll(coll2);

        // 使用并行流优化
        Stream<T> stream = useParallel ? allElements.parallelStream() : allElements.stream();
        return stream
                .flatMap(t -> {
                    int count = Math.max(map1.getOrDefault(t, 0), map2.getOrDefault(t, 0));
                    return Stream.generate(() -> t).limit(count);
                })
                .collect(Collectors.toList());
    }

    /**
     * 两个集合的交集
     * 针对一个集合中存在多个相同元素的情况，计算两个集合中此元素的个数，保留最少的个数
     *
     * @param <T>   集合元素类型
     * @param coll1 集合1
     * @param coll2 集合2
     * @return 交集的集合，返回 {@link ArrayList}
     */
    public static <T> Collection<T> intersection(Collection<T> coll1, Collection<T> coll2) {
        if (isNotEmpty(coll1) && isNotEmpty(coll2)) {
            // 大数据量时使用并行处理
            boolean useParallel = coll1.size() + coll2.size() > PARALLEL_THRESHOLD;

            final Map<T, Integer> map1 = countMap(coll1, useParallel);
            final Map<T, Integer> map2 = countMap(coll2, useParallel);

            Collection<T> elements = new HashSet<>(coll2);

            if (useParallel) {
                // 并行处理时使用线程安全的集合
                List<T> result = Collections.synchronizedList(new ArrayList<>());
                elements.parallelStream().forEach(t -> {
                    int m = Math.min(map1.getOrDefault(t, 0), map2.getOrDefault(t, 0));
                    for (int i = 0; i < m; i++) {
                        result.add(t);
                    }
                });
                return result;
            } else {
                final ArrayList<T> list = new ArrayList<>(Math.min(coll1.size(), coll2.size()));
                for (T t : elements) {
                    int m = Math.min(map1.getOrDefault(t, 0), map2.getOrDefault(t, 0));
                    for (int i = 0; i < m; i++) {
                        list.add(t);
                    }
                }
                return list;
            }
        }

        return new ArrayList<>();
    }

    /**
     * 两个集合的差集
     * 针对一个集合中存在多个相同元素的情况，计算两个集合中此元素的个数，保留两个集合中此元素个数差的个数
     *
     * @param <T>   集合元素类型
     * @param coll1 集合1
     * @param coll2 集合2
     * @return 差集的集合，返回 {@link ArrayList}
     */
    public static <T> Collection<T> disjunction(Collection<T> coll1, Collection<T> coll2) {
        if (isEmpty(coll1)) {
            return coll2;
        }
        if (isEmpty(coll2)) {
            return coll1;
        }

        // 大数据量时使用并行处理
        boolean useParallel = coll1.size() + coll2.size() > PARALLEL_THRESHOLD;

        final Map<T, Integer> map1 = countMap(coll1, useParallel);
        final Map<T, Integer> map2 = countMap(coll2, useParallel);

        Collection<T> allElements = new HashSet<>(coll2);
        allElements.addAll(coll1);

        if (useParallel) {
            // 并行处理时使用线程安全的集合
            List<T> result = Collections.synchronizedList(new ArrayList<>());
            allElements.parallelStream().forEach(t -> {
                int m = Math.abs(map1.getOrDefault(t, 0) - map2.getOrDefault(t, 0));
                for (int i = 0; i < m; i++) {
                    result.add(t);
                }
            });
            return result;
        } else {
            final List<T> result = new ArrayList<>();
            for (T t : allElements) {
                int m = Math.abs(map1.getOrDefault(t, 0) - map2.getOrDefault(t, 0));
                for (int i = 0; i < m; i++) {
                    result.add(t);
                }
            }
            return result;
        }
    }

    /**
     * 计算集合的单差集，即只返回【集合1】中有，但是【集合2】中没有的元素
     *
     * @param coll1 集合1
     * @param coll2 集合2
     * @param <T>   元素类型
     * @return 单差集
     */
    public static <T> Collection<T> subtract(Collection<T> coll1, Collection<T> coll2) {
        if (isEmpty(coll1) || isEmpty(coll2)) {
            return coll1;
        }

        // 大数据量时使用并行处理
        if (coll1.size() > PARALLEL_THRESHOLD) {
            Set<T> coll2Set = new HashSet<>(coll2);
            return coll1.parallelStream()
                    .filter(t -> !coll2Set.contains(t))
                    .collect(Collectors.toList());
        }

        Collection<T> result = new ArrayList<>(coll1);
        result.removeAll(coll2);
        return result;
    }

    /**
     * 判断指定集合是否包含指定值，如果集合为空（null或者空），返回{@code false}，否则找到元素返回{@code true}
     *
     * @param collection 集合
     * @param value      需要查找的值
     * @return 如果集合为空（null或者空），返回{@code false}，否则找到元素返回{@code true}
     */
    public static boolean contains(Collection<?> collection, Object value) {
        if (isEmpty(collection)) {
            return false;
        }

        // 大数据量时使用并行处理
        if (collection.size() > PARALLEL_THRESHOLD) {
            return collection.parallelStream().anyMatch(t -> Objects.equals(t, value));
        }
        return collection.contains(value);
    }

    /**
     * 判断指定集合是否包含指定值，如果集合为空（null或者空），返回{@code false}，否则找到元素返回{@code true}
     * 该方法会捕获ClassCastException和NullPointerException异常，避免程序崩溃
     *
     * @param collection 集合
     * @param value      需要查找的值
     * @return 如果集合为空（null或者空），返回{@code false}，否则找到元素返回{@code true}
     */
    public static boolean safeContains(Collection<?> collection, Object value) {
        try {
            return contains(collection, value);
        } catch (ClassCastException | NullPointerException e) {
            return false;
        }
    }

    /**
     * 集合分组（空值安全+Stream优化）
     *
     * @param coll       待分组集合
     * @param classifier 分组函数
     * @return 分组结果Map（输入空时返回空Map）
     */
    public static <T, K> Map<K, List<T>> groupBy(
            Collection<T> coll, Function<T, K> classifier) {

        if (isEmpty(coll)) {
            return Collections.emptyMap();
        }

        // 大数据量时使用并行流
        if (coll.size() > PARALLEL_THRESHOLD) {
            return coll.parallelStream().collect(Collectors.groupingByConcurrent(classifier));
        }
        return coll.stream().collect(Collectors.groupingBy(classifier));
    }

    /**
     * 安全获取列表元素（空值安全+索引校验）
     *
     * @param list  目标列表
     * @param index 元素索引
     * @return 存在时返回元素，否则返回null
     */
    public static <T> T getSafe(List<T> list, int index) {
        return getSafe(list, index, null);
    }

    /**
     * 安全获取列表元素（带默认值）
     *
     * @param list         目标列表
     * @param index        元素索引
     * @param defaultValue 默认返回值
     * @return 存在时返回元素，否则返回默认值
     */
    public static <T> T getSafe(List<T> list, int index, T defaultValue) {
        if (isEmpty(list) || index < 0 || index >= list.size()) {
            return defaultValue;
        } else {
            return list.get(index);
        }
    }

    /**
     * 安全获取Map值（空值安全）
     *
     * @param map 目标Map
     * @param key 查找键
     * @return 存在时返回值，否则返回null
     */
    public static <K, V> V getSafe(Map<K, V> map, K key) {
        return getSafe(map, key, null);
    }

    /**
     * 安全获取Map值（带默认值）
     *
     * @param map          目标Map
     * @param key          查找键
     * @param defaultValue 默认返回值
     * @return 存在时返回值，否则返回默认值
     */
    public static <K, V> V getSafe(Map<K, V> map, K key, V defaultValue) {
        if (isEmpty(map) || key == null) {
            return defaultValue;
        } else {
            return map.getOrDefault(key, defaultValue);
        }
    }

    /**
     * 安全创建集合（空值安全）
     *
     * @param coll 原始集合
     * @return 非空时返回原集合，否则返回空集合
     */
    public static <T> Collection<T> safe(Collection<T> coll) {
        return coll != null ? coll : Collections.emptyList();
    }

    /**
     * 安全创建Map（空值安全）
     *
     * @param map 原始Map
     * @return 非空时返回原Map，否则返回空Map
     */
    public static <K, V> Map<K, V> safe(Map<K, V> map) {
        return map != null ? map : Collections.emptyMap();
    }

    /**
     * 计算集合中每个元素出现的次数
     *
     * @param <T>         元素类型
     * @param coll        集合
     * @param useParallel 是否使用并行处理
     * @return 元素出现次数的Map
     */
    private static <T> Map<T, Integer> countMap(Collection<T> coll, boolean useParallel) {
        if (useParallel) {
            return coll.parallelStream()
                    .collect(Collectors.toConcurrentMap(
                            k -> k,
                            v -> 1,
                            Integer::sum
                    ));
        } else {
            final Map<T, Integer> map = new HashMap<>();
            for (T t : coll) {
                map.put(t, map.getOrDefault(t, 0) + 1);
            }
            return map;
        }
    }

    /**
     * 计算集合中每个元素出现的次数（默认串行处理）
     *
     * @param <T>  元素类型
     * @param coll 集合
     * @return 元素出现次数的Map
     */
    private static <T> Map<T, Integer> countMap(Collection<T> coll) {
        return countMap(coll, false);
    }
}